package com.javaex.book.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.params.SetParams;
import redis.clients.jedis.resps.ScanResult;


public class JedisUtils {

	private static final Logger logger = LoggerFactory.getLogger(JedisUtils.class);
	
	/** 数据默认过期时间 30 分钟 */
	public static final Long DEFAULT_TIMEOUT_SECONDS = (long) (60 * 30);
	
	private static JedisPool jedisPool;
	
	static {
		// 读取配置文件
		Properties properties = new Properties();
		InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
		try {
			properties.load(is);
		} catch (IOException e) {
			logger.error("Jedis配置文件读取失败", e);
		}
		
		// 连接池相关配置
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal((Integer) properties.getOrDefault("maxTotal", JedisPoolConfig.DEFAULT_MAX_TOTAL));
		config.setMaxIdle((Integer) properties.getOrDefault("maxIdel", JedisPoolConfig.DEFAULT_MAX_IDLE));
		
		// 创建连接池
		String host = (String) properties.getOrDefault("host", "127.0.0.1");
		Integer port = Integer.parseInt((String) properties.getOrDefault("port", "6379"));
		jedisPool = new JedisPool(config, host, port);
		logger.info("创建Jedis连接池");
	}
	
	/**
	 * 获取jedis连接
	 * @return jedis连接
	 */
	private static Jedis getConnection() {
		return jedisPool.getResource();
	}
	
	/**
	 * 关闭Jedis连接
	 * @param jedis jedis连接
	 */
	private static void closeJedis(Jedis jedis) {
		if (jedis == null) {
			return;
		}
		jedis.close();
	}
	
	/**
	 * 关闭Jedis连接池
	 */
	public static void closeJedisPool() {
		if (jedisPool == null) {
			return;
		}
		logger.info("关闭Jedis连接池");
		jedisPool.close();
	}
	
	/**
	 * 设置数据
	 * @param key 键
	 * @param value 值
	 */
	public static void setObj(String key, Object value) {
		set(key, JsonUtils.stringify(value));
	}
	
	/**
	 * 设置数据
	 * @param key 键
	 * @param value 值
	 */
	public static void set(String key, String value) {
		Jedis jedis = getConnection();
		jedis.set(key, value, new SetParams().ex(DEFAULT_TIMEOUT_SECONDS));
		closeJedis(jedis);
	}
	
	/**
	 * 取String类型数据
	 * @param key
	 * @return String类型数据
	 */
	public static String get(String key) {
		Jedis jedis = getConnection();
		try {
			return jedis.get(key);
		} finally {
			closeJedis(jedis);
		}
	}

	/**
	 * 获取Integer类型数据
	 * @param key
	 * @return Integer类型数据
	 */
	public static Integer getInteger(String key) {
		try {
			return Integer.parseInt(get(key));
		} catch (Exception e) {
			return null;
		} 
	}
	
	/**
	 * 取引用类型数据
	 * @param <T> 要取出的数据类型
	 * @param key 键
	 * @param clazz 数据类型的Class对象
	 * @return 取出的数据
	 */
	public static <T> T getObj(String key, Class<T> clazz) {
		String dataStr = get(key);
		if (dataStr == null) {
			return null;
		}
		return JsonUtils.parse(dataStr, clazz);
	}
	
	/**
	 * 取出数据集合
	 * @param <T> 数据类型
	 * @param key 
	 * @return 数据集合
	 */
	public static <T> List<T> getList(String key) {
		String json = get(key);
		if (json == null) {
			return null;
		}
		return JsonUtils.parseToList(json);
	}
	
	/**
	 * 删除数据
	 * @param key 数据的key
	 */
	public static void deleteOne(String key) {
		Jedis jedis = getConnection();
		try {
			jedis.del(key);
		} finally {
			closeJedis(jedis);
		}
	}
	
	/**
	 * 查找所有匹配的key
	 * @param jedis Jedis连接
	 * @param pattern key匹配规则
	 * @return 包含所有匹配key的Set集合
	 */
	private static Set<String> findKeys(Jedis jedis, String pattern) {
		ScanParams params = new ScanParams();
		params.match(pattern);
		params.count(10);
		String cursor = "0";
		Set<String> keySet = new HashSet<>();
		do {
			ScanResult<String> result = jedis.scan(cursor, params);
			List<String> list = result.getResult();
			cursor = result.getCursor();
			keySet.addAll(list);
		} while (!cursor.equals("0"));
		return keySet;
	}
	
	/**
	 * 删除多个key
	 */
	public static void deleteMany(String pattern) {
		Jedis jedis = getConnection();
		try {
			Set<String> keys = findKeys(jedis, pattern);
			for (String key : keys) {
				jedis.del(key);
			}
		} finally {
			closeJedis(jedis);
		}
	}
}
